package middle;

import java.util.*;

/**
 * MT4 直方图内最大矩形
 * @author d3y1
 */
public class MT4{
    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     *
     * @param heights int整型一维数组
     * @return int整型
     */
    public int largestRectangleArea (int[] heights) {
        return solution1(heights);
//        return solution2(heights);
    }

    /**
     * 单调栈
     * @param heights
     * @return
     */
    private int solution1(int[] heights){
        int N = heights.length;

        Map<Integer, Integer> rightMap = new HashMap<Integer, Integer>();
        Map<Integer, Integer> leftMap = new HashMap<Integer, Integer>();
        Deque<Integer> rightStack = new ArrayDeque<Integer>();
        Deque<Integer> leftStack = new ArrayDeque<Integer>();
        int height;
        for (int i=N-1; i>=0; i--){
            // 找到当前元素右边第一个小于当前元素的元素索引 N:表示没找到, 当前元素右边都比当前元素大
            height = heights[i];
            while (!rightStack.isEmpty() && height<=heights[rightStack.peek()]){
                rightStack.pop();
            }
            rightMap.put(i, rightStack.isEmpty() ? N : rightStack.peek());
            rightStack.push(i);

            // 找到当前元素左边第一个小于当前元素的元素索引 -1:表示没找到, 当前元素左边都比当前元素大
            height = heights[N-i-1];
            while (!leftStack.isEmpty() && height<=heights[leftStack.peek()]){
                leftStack.pop();
            }
            leftMap.put(N-i-1, leftStack.isEmpty() ? -1 : leftStack.peek());
            leftStack.push(N-i-1);
        }

        int square = 0;
        for(int i=0; i<N; i++){
            square = Math.max(square, heights[i]*(rightMap.get(i)-leftMap.get(i)-1));
        }

        return square;
    }

    /**
     * 模拟法: 超时
     */
    private int solution2(int[] heights){
        int len = heights.length;
        int square = 0;
        for(int i=0; i<len; i++){
            int height = Integer.MAX_VALUE;
            for(int j=i; j>=0; j--){
                height = Math.min(height, heights[j]);
                square = Math.max(square, height*(i-j+1));
            }
        }

        return square;
    }
}